package com.pku.smart.trade.channel.alipay;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.domain.*;
import com.alipay.api.request.*;
import com.alipay.api.response.*;
import com.pku.smart.ali.model.builder.AlipayTradePayRequestBuilder;
import com.pku.smart.ali.model.result.AlipayF2FPayResult;
import com.pku.smart.ali.service.AlipayTradeService;
import com.pku.smart.constant.PayConstant;
import com.pku.smart.log.MyLog;
import com.pku.smart.trade.entity.TradePayGoodsDetails;
import com.pku.smart.trade.exception.BizAliPayException;
import org.apache.commons.lang3.StringUtils;

import java.util.List;

public class AliPayUtils {

    private static final MyLog _log = MyLog.getLog(AliPayUtils.class);

    public static AlipayF2FPayResult tradePay(AlipayTradeService alipayTradeService, String outTradeNo, String authCode, String subject, String totalAmount, String body, String terminalId, String operatorId, List<GoodsDetail> goodsDetailList) throws AlipayApiException {
        ExtendParams extendParams = new ExtendParams();
        extendParams.setSysServiceProviderId(PayConstant.PAY_CHANNEL_ALIPAY_PROVIDER_ID);
        String scene = "bar_code";//支付场景--条码支付，取值：bar_code 声波支付，取值：wave_code
        String timeoutExpress = "5m";// 支付超时，线下扫码交易定义为5分钟
        String undiscountableAmount = "0.0"; //如果该值未传入,但传入了【订单总金额】,【打折金额】,则该值默认为【订单总金额】-【打折金额】
        String sellerId = "";//如果该字段为空，则默认为与支付宝签约的商户的PID，也就是appid对应的PID
        String storeId = terminalId;
        AlipayTradePayRequestBuilder builder = new AlipayTradePayRequestBuilder()
                .setOutTradeNo(outTradeNo).setSubject(subject).setAuthCode(authCode)
                .setTotalAmount(totalAmount).setStoreId(storeId)
                .setUndiscountableAmount(undiscountableAmount)
                .setScene(scene)
                .setBody(body).setOperatorId(operatorId)
                .setExtendParams(extendParams).setSellerId(sellerId)
                .setGoodsDetailList(goodsDetailList)
                .setTimeoutExpress(timeoutExpress);
        AlipayF2FPayResult result = alipayTradeService.tradePay(builder);
        _log.info("支付宝返回结果:{}", JSON.toJSONString(result));
        return result;
    }

    /**
     * 统一收单交易支付接口 alipay.trade.pay
     * 支付宝被扫(扫码设备)
     *
     * @param outTradeNo        商户订单号,64个字符以内、可包含字母、数字、下划线；需保证在商户端不重复
     * @param authCode          支付授权码，25~30开头的长度为16~24位的数字，实际字符串长度以开发者获取的付款码长度为准
     * @param subject           订单标题
     * @param amount            订单总金额
     * @param body              订单描述 可选
     * @param payGoodsDetailses
     * @return
     */
    @Deprecated
    public static JSONObject tradePay(AlipayClient alipayClient, String outTradeNo, String authCode, String subject, String amount, String body, String terminalId, String operatorId, List<TradePayGoodsDetails> payGoodsDetailses) throws AlipayApiException {
        AlipayTradePayModel model = new AlipayTradePayModel();
        ExtendParams extendParams = new ExtendParams();
        extendParams.setSysServiceProviderId(PayConstant.PAY_CHANNEL_ALIPAY_PROVIDER_ID);
        String scene = "bar_code";//支付场景--条码支付，取值：bar_code 声波支付，取值：wave_code
        model.setOutTradeNo(outTradeNo);
        model.setScene(scene);//条码支付，取值：bar_code 声波支付，取值：wave_code
        model.setAuthCode(authCode);//授权码
        model.setSubject(subject);
        model.setTotalAmount(amount);
        model.setBody(body);
        model.setTerminalId(terminalId);
        model.setOperatorId(operatorId);//商户操作员编号 这里传支付平台商户号
        model.setExtendParams(extendParams);
        AlipayTradePayRequest alipay_request = new AlipayTradePayRequest();
        alipay_request.setBizModel(model);

        AlipayTradePayResponse response = alipayClient.execute(alipay_request);
        JSONObject responseJSON = JSONObject.parseObject(JSONObject.toJSONString(response));
        _log.info("支付宝返回结果:{}", responseJSON);
        return responseJSON;
    }

    /**
     * 统一收单线下交易查询 alipay.trade.query
     *
     * @param alipayClient
     * @param outTradeNo   商户订单号
     * @param subject      订单标题
     * @param amount       订单总金额
     * @param body         商品描述信息 可选
     * @param device       商户机具终端编号 可选
     * @param extra        打折金额拼接
     * @return
     */
    public static JSONObject tradePrecreate(AlipayClient alipayClient, String outTradeNo, String subject, String amount, String body, String device, String extra, String notifyUrl) throws AlipayApiException {
        AlipayTradePrecreateModel model = new AlipayTradePrecreateModel();
        ExtendParams extendParams = new ExtendParams();
        extendParams.setSysServiceProviderId(PayConstant.PAY_CHANNEL_ALIPAY_PROVIDER_ID);
        model.setOutTradeNo(outTradeNo);
        model.setSubject(subject);
        model.setTotalAmount(String.valueOf(amount));
        model.setBody(body);
        model.setTerminalId(device);
        model.setOperatorId("");//商户操作员编号 这里传支付平台商户号
        model.setExtendParams(extendParams);
        if (StringUtils.isNotEmpty(extra)) {
            JSONObject objParamsJson = JSON.parseObject(extra);
            if (StringUtils.isNotBlank(objParamsJson.getString("discountable_amount"))) {
                _log.info("可打折金额");
                model.setDiscountableAmount(objParamsJson.getString("discountable_amount"));
            }
            if (StringUtils.isNotBlank(objParamsJson.getString("undiscountable_amount"))) {
                _log.info("不可打折金额");
                model.setUndiscountableAmount(objParamsJson.getString("undiscountable_amount"));
            }
        }
        AlipayTradePrecreateRequest alipay_request = new AlipayTradePrecreateRequest();
        alipay_request.setBizModel(model);
        alipay_request.setNotifyUrl(notifyUrl);

        AlipayTradePrecreateResponse response = alipayClient.execute(alipay_request);
        JSONObject responseJSON = JSONObject.parseObject(JSONObject.toJSONString(response));
        _log.info("支付宝返回结果:{}", responseJSON);
        return responseJSON;
    }

    /**
     * 统一收单线下交易查询 alipay.trade.query
     *
     * @param alipayClient
     * @param tradeNo      商户订单号 和支付宝交易号不能同时为空
     * @param outTradeNo   渠道订单号 支付宝交易号，和商户订单号不能同时为空
     * @return
     */
    public static JSONObject tradeQuery(AlipayClient alipayClient, String tradeNo, String outTradeNo) throws AlipayApiException {
        AlipayTradeQueryModel model = new AlipayTradeQueryModel();
        model.setOutTradeNo(outTradeNo);//商户订单号
        model.setTradeNo(tradeNo);
        AlipayTradeQueryRequest alipay_request = new AlipayTradeQueryRequest();
        alipay_request.setBizModel(model);

        AlipayTradeQueryResponse response = alipayClient.execute(alipay_request);
        JSONObject responseJSON = JSONObject.parseObject(JSONObject.toJSONString(response));
        _log.info("支付宝订单查询返回结果:{}", responseJSON);
        return responseJSON;
    }

    /**
     * 统一收单交易撤销接口 alipay.trade.cancel
     *
     * @param alipayClient
     * @param tradeNo      原支付请求的商户订单号
     * @param outTradeNo   支付宝交易号，和商户订单号不能同时为空
     * @return
     */
    public static JSONObject tradeCancel(AlipayClient alipayClient, String tradeNo, String outTradeNo) throws AlipayApiException {
        AlipayTradeCancelModel model = new AlipayTradeCancelModel();
        model.setOutTradeNo(outTradeNo);
        model.setTradeNo(tradeNo);
        AlipayTradeCancelRequest alipay_request = new AlipayTradeCancelRequest();
        alipay_request.setBizModel(model);

        AlipayTradeCancelResponse response = alipayClient.execute(alipay_request);
        JSONObject responseJSON = JSONObject.parseObject(JSONObject.toJSONString(response));
        _log.info("支付宝订单撤销返回结果:{}", responseJSON);
        return responseJSON;
    }

    /**
     * 统一收单交易退款接口 alipay.trade.refund
     *
     * @param alipayClient
     * @param tradeNo      订单支付时传入的商户订单号
     * @param outTradeNo   订单支付时传入的渠道订单号
     * @param outRequestNo 标识一次退款请求，同一笔交易多次退款需要保证唯一，如需部分退款，则此参数必传。
     * @param refundAmount 需要退款的金额，该金额不能大于订单金额,单位为元，支持两位小数
     * @param refundReason 退款的原因说明
     * @return
     */
    public static JSONObject tradeRefund(AlipayClient alipayClient, String tradeNo, String outTradeNo, String outRequestNo, String refundAmount, String refundReason) throws AlipayApiException {
        AlipayTradeRefundModel model = new AlipayTradeRefundModel();
        model.setOutTradeNo(outTradeNo);
        model.setTradeNo(tradeNo);
        model.setOutRequestNo(outRequestNo);
        model.setRefundAmount(refundAmount);
        model.setRefundReason(refundReason);
        AlipayTradeRefundRequest alipay_request = new AlipayTradeRefundRequest();
        alipay_request.setBizModel(model);

        AlipayTradeRefundResponse response = alipayClient.execute(alipay_request);
        JSONObject responseJSON = JSONObject.parseObject(JSONObject.toJSONString(response));
        _log.info("支付宝订单退款返回结果:{}", responseJSON);
        return responseJSON;
    }

    /**
     * 统一收单交易退款查询 alipay.trade.fastpay.refund.query
     *
     * @param alipayClient
     * @param tradeNo      支付宝交易号，和商户订单号不能同时为空
     * @param outTradeNo   订单支付时传入的商户订单号,和支付宝交易号不能同时为空。 trade_no,out_trade_no如果同时存在优先取trade_no
     * @param outRequestNo 请求退款接口时，传入的退款请求号，如果在退款请求时未传入，则该值为创建交易时的外部交易号
     * @return
     */
    public static JSONObject tradeRefundQuery(AlipayClient alipayClient, String tradeNo, String outTradeNo, String outRequestNo) throws AlipayApiException {
        AlipayTradeFastpayRefundQueryModel model = new AlipayTradeFastpayRefundQueryModel();
        model.setOutTradeNo(outTradeNo);
        model.setTradeNo(tradeNo);
        model.setOutRequestNo(outRequestNo);
        AlipayTradeFastpayRefundQueryRequest alipay_request = new AlipayTradeFastpayRefundQueryRequest();
        alipay_request.setBizModel(model);

        AlipayTradeFastpayRefundQueryResponse response = alipayClient.execute(alipay_request);
        JSONObject responseJSON = JSONObject.parseObject(JSONObject.toJSONString(response));
        _log.info("支付宝订单退款查询返回结果:{}", responseJSON);
        return responseJSON;
    }

    /**
     * 手机网站支付接口2.0 alipay.trade.wap.pay
     *
     * @param alipayClient
     * @param outTradeNo   商户网站唯一订单号
     * @param subject      商品的标题/交易标题/订单标题/订单关键字等
     * @param totalAmount  订单总金额，单位为元
     * @param body         对一笔交易的具体描述信息
     * @param quitUrl      用户付款中途退出返回商户网站的地址
     * @param prodCode     销售产品码，商家和支付宝签约的产品码 QUICK_WAP_WAY
     * @param notifyUrl    支付宝服务器主动通知商户服务器里指定的页面
     * @param returnUrl
     * @return
     * @throws AlipayApiException
     */
    public static JSONObject tradeWappay(AlipayClient alipayClient, String outTradeNo, String subject, String totalAmount, String body, String quitUrl, String prodCode, String notifyUrl, String returnUrl) throws AlipayApiException {
        AlipayTradeWapPayModel model = new AlipayTradeWapPayModel();
        ExtendParams extendParams = new ExtendParams();
        extendParams.setSysServiceProviderId(PayConstant.PAY_CHANNEL_ALIPAY_PROVIDER_ID);
        model.setOutTradeNo(outTradeNo);
        model.setSubject(subject);
        model.setTotalAmount(totalAmount);
        model.setBody(body);
        model.setQuitUrl(quitUrl);
        model.setProductCode(prodCode);
        model.setExtendParams(extendParams);
        AlipayTradeWapPayRequest alipay_request = new AlipayTradeWapPayRequest();
        alipay_request.setBizModel(model);
        alipay_request.setNotifyUrl(notifyUrl);
        alipay_request.setReturnUrl(returnUrl);

        AlipayTradeWapPayResponse response = alipayClient.pageExecute(alipay_request);
        JSONObject responseJSON = JSONObject.parseObject(JSONObject.toJSONString(response));
        responseJSON.put("code", "10000");
        _log.info("支付宝WAP支付返回结果:{}", responseJSON);
        return responseJSON;
    }

    /**
     * 对账单下载
     * @param alipayClient
     * @param dateStr
     * @return
     * @throws AlipayApiException
     */
    public static JSONObject tradeBillDown(AlipayClient alipayClient, String dateStr) throws AlipayApiException {
        AlipayDataDataserviceBillDownloadurlQueryRequest alipay_request = new AlipayDataDataserviceBillDownloadurlQueryRequest();
        alipay_request.setBizContent("{" +
                "  \"bill_type\":\"trade\"," +
                "  \"bill_date\":"+
                "  \"" + dateStr + "\"" +
                "}");
        AlipayDataDataserviceBillDownloadurlQueryResponse response = alipayClient.execute(alipay_request);
        JSONObject responseJSON = JSONObject.parseObject(JSONObject.toJSONString(response));
        _log.info("支付宝订单退款查询返回结果:{}", responseJSON);
        return responseJSON;
    }

    /**
     * 校验
     *
     * @param response
     * @param checkSuccess
     * @throws BizAliPayException
     */
    //private static void checkResult(AlipayResponse response, boolean checkSuccess) throws BizAliPayException {
    //    if (checkSuccess) {
    //        if ("10000".equals(response.getCode()) && response.isSuccess()) {
    //
    //        } else {
    //            StringBuilder errorMsg = new StringBuilder();
    //            if (response.getCode() != null) {
    //                errorMsg.append("返回代码：").append(response.getCode());
    //            }
    //            if (response.getMsg() != null) {
    //                errorMsg.append("返回信息：").append(response.getMsg());
    //            }
    //            if (response.getSubCode() != null) {
    //                errorMsg.append("，错误代码：").append(response.getSubCode());
    //            }
    //            if (response.getSubMsg() != null) {
    //                errorMsg.append("，错误详情：").append(response.getSubMsg());
    //            }
    //            if (response.getBody() != null) {
    //                errorMsg.append("，具体内容：").append(response.getBody());
    //            }
    //            _log.error("结果业务代码异常，返回结果：{}", errorMsg.toString());
    //            throw BizAliPayException.from(response);
    //        }
    //    }
    //}
}
